package edu.hitsz.application;

import edu.hitsz.aircraft.*;
import edu.hitsz.bullet.BaseBullet;
import edu.hitsz.basic.AbstractFlyingObject;
import edu.hitsz.factory.aircraft.AircraftFactory;
import edu.hitsz.factory.aircraft.BossAircraftFactory;
import edu.hitsz.factory.aircraft.EliteAircraftFactory;
import edu.hitsz.factory.aircraft.MobAircraftFactory;
import edu.hitsz.factory.prop.BloodPropFactory;
import edu.hitsz.factory.prop.BombPropFactory;
import edu.hitsz.factory.prop.BulletPropFactory;
import edu.hitsz.factory.prop.PropFactory;
import edu.hitsz.observer.BombObserver;
import edu.hitsz.prop.AbstractProp;
import edu.hitsz.prop.BloodProp;
import edu.hitsz.prop.BombProp;
import edu.hitsz.prop.BulletProp;
import edu.hitsz.rankinglist.Rank;
import edu.hitsz.rankinglist.RankDaoImpl;


import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.*;
import java.util.List;
import java.util.concurrent.*;

import static edu.hitsz.application.ImageManager.*;

/**
 * 游戏主面板，游戏启动
 *
 * @author hitsz
 */
public class Game extends JPanel {

    protected int backGroundTop = 0;

    /**
     * Scheduled 线程池，用于任务调度
     */
    protected final ScheduledExecutorService executorService;

    /**
     * 时间间隔(ms)，控制刷新频率
     */
    protected int timeInterval = 40;

    protected final HeroAircraft heroAircraft;
    protected final List<AbstractAircraft> enemyAircrafts;
    protected final List<BaseBullet> heroBullets;
    protected final List<BaseBullet> enemyBullets;
    protected final List<AbstractProp> props;

    protected MusicThread bgm;
    protected MusicThread bossBgm;


    /** 最多同时出现5架敌机 1架boss战机*/
    protected int enemyMaxNumber = 5;
    protected int bossNumber = 0;

    protected boolean gameOverFlag = false;
    protected int score = 0;
    protected int time = 0;

    /** 下一次boss机出现的分数阈值 */
    protected int bossScore = 100;
    protected int bossInterval = 1000;

    /** 指导普通敌机产生概率 */
    protected int mobChoice = 75;
    /**
     * 周期（ms)
     * 指示子弹的发射、敌机的产生频率和各种子弹发射频率
     */
    protected int cycleDuration = 600;
    protected int cycleTime = 0;
    protected int counter = 0;
    protected int counterEnd = 3;

    /** 难度模式 */
    protected int modeType;

    /** 背景图片 */
    protected BufferedImage background;

    /** 音效开关 */
    protected boolean musicSwitch;

    /** 排行榜 */
    protected RankDaoImpl Ranks;

    /** 用户名 */
    protected String userName;

    /** 排行榜文件路径 */
    protected String rankFile;

    /** 炸弹道具观察者 */
    protected BombObserver bombObserver;

    /** 敌机血量 */
    protected int mobHp = 30;
    protected int eliteHp = 90;
    protected int bossHp = 300;

    /** 难度变化周期 */
    protected int increaseDiffCircle;
    protected int diffDegree = 0;

    public Game(boolean musicSwitch,String userName) {
        // 英雄战机最初出现在屏幕正中间最下方 初始生命值为100
        heroAircraft = HeroAircraft.getInstance();

        enemyAircrafts = new LinkedList<>();
        heroBullets = new LinkedList<>();
        enemyBullets = new LinkedList<>();
        props = new LinkedList<>();


        //Scheduled 线程池，用于定时任务调度
        executorService = new ScheduledThreadPoolExecutor(1);

        //启动英雄机鼠标监听
        new HeroController(this, heroAircraft);

        this.musicSwitch = musicSwitch;

        // 用户名
        this.userName = userName;

        if(this.userName.equals("")){
            this.userName = "匿名玩家";
        }

        // 炸弹道具观察者
        bombObserver = new BombObserver();
    }

    /**
     * 游戏启动入口，执行游戏逻辑
     */
    public void action() {

        // 循环播放bgm
        bgm = new MusicThread("src/videos/bgm.wav",1);
        bossBgm = new MusicThread("src/videos/bgm_boss.wav",1);

        if(musicSwitch) {
            bgm.start();
        }

        // 定时任务：绘制、对象产生、碰撞判定、击毁及结束判定
        Runnable task = () -> {
            time += timeInterval;

            // 周期性执行（控制频率）
            if (timeCountAndNewCycleJudge()) {

                // 控制子弹发射频率
                ++counter;
                counter %= counterEnd;

                System.out.println(time);

                // 产生敌机
                generateEnemy();

                // 飞机射出子弹
                shootAction();
            }

            // 子弹移动
            bulletsMoveAction();

            // 飞机移动
            aircraftsMoveAction();

            // 道具移动
            propsMoveAction();

            // 撞击检测
            crashCheckAction();

            // 后处理
            postProcessAction();

            // 每个时刻重绘界面
            repaint();

            // 难度增加
            increaseDifficulty();

            // 游戏结束检查
            if (heroAircraft.getHp() <= 0) {

                // 处理排行榜
                processRankList();

                // 游戏结束
                executorService.shutdown();
                gameOverFlag = true;

                // 停止播放bgm
                bgm.pause();
                bossBgm.pause();

                // 游戏结束特效音
                if(musicSwitch) {
                    new MusicThread("src/videos/game_over.wav", 0).start();
                }

                System.out.println("Game Over!");

                // 唤醒排行榜页面
                synchronized (this) {
                    this.notify();
                }
            }

        };

        /**
         * 以固定延迟时间进行执行
         * 本次任务执行完成后，需要延迟设定的延迟时间，才会执行新的任务
         */
        executorService.scheduleWithFixedDelay(task, timeInterval, timeInterval, TimeUnit.MILLISECONDS);

    }

    //***********************
    //      Action 各部分
    //***********************

    /** 时间周期检测 */
    protected boolean timeCountAndNewCycleJudge() {
        cycleTime += timeInterval;
        // 如果刚好超出当前时间周期
        if (cycleTime >= cycleDuration && cycleTime - timeInterval < cycleTime) {
            // 跨越到新的周期
            cycleTime %= cycleDuration;
            return true;
        } else {
            return false;
        }
    }

    /** 产生敌机 */
    protected void generateEnemy() {
        // 是否产生新敌机
        if (enemyAircrafts.size() < enemyMaxNumber) {
            // 是否产生boss机
            if(score >= bossScore && bossNumber == 0){
                enemyAircrafts.add(new BossAircraftFactory().createAircraft(bossHp));
                bossNumber = 1;

                // 循环播放BossBgm
                bgm.pause();
                bossBgm = new MusicThread("src/videos/bgm_boss.wav",1);
                if(musicSwitch){
                    bossBgm.start();
                }
            }
            // 如果不产生boss机再考虑产生其他机型
            else{
                // 概率生成新敌机
                Random r =new Random();
                int choice = r.nextInt(100);

                // 3/4概率生成普通敌机 1/4概率生成精英敌机
                if (choice < mobChoice) {
                    AbstractAircraft enemy = new MobAircraftFactory().createAircraft(mobHp);
                    enemyAircrafts.add(enemy);
                    bombObserver.subscribe(enemy);
                }
                else{
                    AbstractAircraft enemy = new EliteAircraftFactory().createAircraft(eliteHp);
                    enemyAircrafts.add(enemy);
                    bombObserver.subscribe(enemy);
                }
            }
        }
    }


    /** 射击 */
    protected void shootAction() {
        // 敌机射击
        for (AbstractAircraft enemyAircraft : enemyAircrafts) {
            // 敌机每3个周期发射一次子弹
            if(counter == 0 && enemyAircraft.getType() >= 2) {
                List<BaseBullet> enemyBullet = enemyAircraft.shoot();
                enemyBullets.addAll(enemyBullet);
                bombObserver.subscribeAll(enemyBullet);
            }
        }

        // 英雄射击
        heroBullets.addAll(heroAircraft.shoot());
        if(heroAircraft.isShootScattering()){
            if(musicSwitch) {
                new MusicThread("src/videos/bullet.wav", 0).start();
            }
        }

    }

    protected void increaseDifficulty(){}

    /** 子弹移动 */
    protected void bulletsMoveAction() {
        for (BaseBullet bullet : heroBullets) {
            bullet.forward();
        }
        for (BaseBullet bullet : enemyBullets) {
            bullet.forward();
        }
    }

    /** 飞机移动 */
    protected void aircraftsMoveAction() {
        for (AbstractAircraft enemyAircraft : enemyAircrafts) {
            enemyAircraft.forward();
        }
    }

    /** 道具移动 */
    protected  void propsMoveAction() {
        for (AbstractProp prop : props) {
            prop.forward();
        }
    }


    /**
     * 碰撞检测：
     * 1. 敌机攻击英雄
     * 2. 英雄攻击/撞击敌机
     * 3. 英雄获得补给
     */
    protected void crashCheckAction() {
        // 敌机子弹攻击英雄
        for (BaseBullet bullet : enemyBullets) {
            // 子弹无效
            if (bullet.notValid()) {continue;}
            // 英雄战机撞到敌方子弹
            if (heroAircraft.crash(bullet)) {
                heroAircraft.decreaseHp(bullet.getPower());
                bullet.vanish();
            }
        }
        // 英雄子弹攻击敌机
        for (BaseBullet bullet : heroBullets) {
            // 子弹无效
            if (bullet.notValid()) {continue;}
            // 对每一架敌机进行判断 是否碰撞
            for (AbstractAircraft enemyAircraft : enemyAircrafts) {
                if (enemyAircraft.notValid()) {
                    // 已被其他子弹击毁的敌机，不再检测 避免多个子弹重复击毁同一敌机的判定
                    continue;
                }
                if (enemyAircraft.crash(bullet)) {
                    // 子弹攻击敌机的bgm
                    if(musicSwitch) {
                        new MusicThread("src/videos/bullet_hit.wav", 0).start();
                    }
                    // 敌机撞击到英雄机子弹 敌机损失一定生命值
                    enemyAircraft.decreaseHp(bullet.getPower());
                    bullet.vanish();
                    // 敌机坠毁
                    if (enemyAircraft.notValid()) {
                        AbstractProp newProp = enemyAircraft.dropProp();
                        if(newProp != null){
                            props.add(newProp);
                        }
                        if(enemyAircraft.getType() == 3) {
                            bossBgm.pause();
                            bgm = new MusicThread("src/videos/bgm.wav",1);
                            if(musicSwitch) {
                                bgm.start();
                            }
                            bossNumber = 0;
                            bossScore = score + bossInterval;
                            System.out.println("当前boss战机已被击毁，下一次boss产生的分数阈值为: " + bossScore);
                        }
                    }
                }
                // 英雄机 与 敌机 相撞，均损毁
                if (enemyAircraft.crash(heroAircraft) || heroAircraft.crash(enemyAircraft)) {
                    enemyAircraft.vanish();
                    heroAircraft.decreaseHp(Integer.MAX_VALUE);
                }
            }
        }
        // 玩家获得道具，道具生效
        for(AbstractProp prop : props){
            if(prop.notValid()) {
                continue;
            }

            // 获得道具
            if(heroAircraft.crash(prop)){
                if(musicSwitch) {
                    new MusicThread("src/videos/get_supply.wav", 0).start();
                }
                Runnable r1 = () -> {
                    if(prop.getType() == 2) {
                        synchronized (this) {
                            try {
                                prop.takeEffect(heroAircraft);
                                Thread.sleep(10000);
                                prop.loseEffect(heroAircraft);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                    else if(prop.getType()==0){
                        prop.takeEffect(heroAircraft);
                    }
                    else{
                        prop.takeEffect(bombObserver);
                    }
                };
                // 道具生效
                new Thread(r1,"道具线程").start();
                // 道具被获得后消失
                prop.vanish();
            }
        }
    }

    /** 排行榜处理 */
    protected void processRankList(){
        try {
            // 读取rankList信息并打印排行榜
            File rankList = new File(rankFile);
            DataInputStream in = new DataInputStream(new FileInputStream(rankList));
            BufferedReader d  = new BufferedReader(new InputStreamReader(in));
            LinkedList<Rank> ranks = new LinkedList<Rank>();
            String count;
            while ((count = d.readLine()) != null){
                int score = Integer.parseInt(count);
                String user = d.readLine();
                String time = d.readLine();
                ranks.add(new Rank(score,user,time));
            }
            Ranks = new RankDaoImpl(ranks);
            String curTime = new java.sql.Timestamp(System.currentTimeMillis()).toString();
            Ranks.addRank(new Rank(score,userName,curTime.substring(0,19)));
            Ranks.printRankingList();
            d.close();

            // 将新数据写入数据文件
            rankList.delete();
            FileOutputStream fop = new FileOutputStream(rankList);
            OutputStreamWriter writer = new OutputStreamWriter(fop, "UTF-8");
            ranks = Ranks.getAllRank();
            for(Rank r: ranks){
                writer.append(r.getScore()+"\r\n");
                writer.append(r.getUserName()+"\r\n");
                writer.append(r.getTime()+"\r\n");
            }
            writer.close();
            fop.close();

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 后处理：
     * 1. 删除无效的子弹
     * 2. 删除无效的敌机
     * 3. 检查英雄机生存
     * 4. 删除无效的道具
     * <p>
     * 无效的原因可能是撞击或者飞出边界或者道具被获取
     */
    protected void postProcessAction() {
        // 加分
        for(AbstractAircraft enemyAircraft:enemyAircrafts){
            if(enemyAircraft.notValid()) {
                if (enemyAircraft.getType() == 1) {
                    score += 10;
                } else if (enemyAircraft.getType() == 2) {
                    score += 50;
                }
                else {
                    score += 300;
                }
            }
        }

        enemyBullets.removeIf(AbstractFlyingObject::notValid);
        heroBullets.removeIf(AbstractFlyingObject::notValid);
        enemyAircrafts.removeIf(AbstractFlyingObject::notValid);
        props.removeIf(AbstractFlyingObject::notValid);
    }


    //***********************
    //      Paint 各部分
    //***********************

    /**
     * 重写paint方法
     * 通过重复调用paint方法，实现游戏动画
     *
     * @param  g
     */
    @Override
    public void paint(Graphics g) {
        super.paint(g);

        // 绘制背景,图片滚动
        g.drawImage(background, 0, this.backGroundTop - Main.WINDOW_HEIGHT, null);
        g.drawImage(background, 0, this.backGroundTop, null);
        this.backGroundTop += 1;
        if (this.backGroundTop == Main.WINDOW_HEIGHT) {
            this.backGroundTop = 0;
        }

        // 先绘制子弹，后绘制飞机 再绘制道具
        // 这样子弹显示在飞机的下层
        paintImageWithPositionRevised(g, enemyBullets);

        paintImageWithPositionRevised(g, heroBullets);

        paintImageWithPositionRevised(g, enemyAircrafts);
        paintImageWithPositionRevised(g, props);




        g.drawImage(ImageManager.HERO_IMAGE, heroAircraft.getLocationX() - ImageManager.HERO_IMAGE.getWidth() / 2,
                heroAircraft.getLocationY() - ImageManager.HERO_IMAGE.getHeight() / 2, null);

        //绘制得分和生命值
        paintScoreAndLife(g);

    }

    protected void paintImageWithPositionRevised(Graphics g, List<? extends AbstractFlyingObject> objects) {
        if (objects.size() == 0) {
            return;
        }

        for (AbstractFlyingObject object : objects) {
            BufferedImage image = object.getImage();
            assert image != null : objects.getClass().getName() + " has no image! ";
            g.drawImage(image, object.getLocationX() - image.getWidth() / 2,
                    object.getLocationY() - image.getHeight() / 2, null);
        }
    }

    protected void paintScoreAndLife(Graphics g) {
        int x = 10;
        int y = 25;
        g.setColor(new Color(16711680));
        g.setFont(new Font("SansSerif", Font.BOLD, 22));
        g.drawString("SCORE:" + this.score, x, y);
        y = y + 20;
        g.drawString("LIFE:" + this.heroAircraft.getHp(), x, y);
    }

    public RankDaoImpl getRanks(){ return Ranks; }
    public int getScore() {return score; }
}
